﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Castle.MicroKernel.Registration;
using System.ComponentModel.Composition;
using Castle.Windsor;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Core;
using Topics.Radical;
using Topics.Radical.Reflection;
using Castle.Facilities.Startable;
using Topics.Radical.ComponentModel.Messaging;
using Topics.Radical.Messaging;
using Topics.Radical.ComponentModel;
using Topics.Radical.Threading;
using SampleApp.MvcBackend.ComponentModel;
using System.Web.Mvc;
using SampleApp.MvcBackend.Services;
using Raven.Client;
using System.Net;
using Raven.Client.Document;
using System.Web.Http;

namespace SampleApp.MvcBackend.Boot.Installers
{
	/// <summary>
	/// Default boot installer.
	/// </summary>
	[Export( typeof( IWindsorInstaller ) )]
	public sealed class DefaultInstaller : IWindsorInstaller
	{
		/// <summary>
		/// Performs the installation in the <see cref="T:Castle.Windsor.IWindsorContainer"/>.
		/// </summary>
		/// <param name="container">The container.</param>
		/// <param name="store">The configuration store.</param>
		public void Install( IWindsorContainer container, IConfigurationStore store )
		{
			var boot = container.Resolve<IHoldBootstrapInformation>();
			var directory = boot.GetBootDirectory();

			container.Register
			(
				Component.For<IWindsorContainer>()
					.Instance( container )
			);

			container.Register
			(
				Component.For<IServiceProvider>()
					.Instance( new ServiceProviderWrapper( container ) )
			);

			container.Register
			(
				Component.For<IControllerFactory>()
					.ImplementedBy<WindsorControllerFactory>()
			);

			container.Register
			(
				AllTypes.FromAssemblyInDirectory( new AssemblyFilter( directory, "SampleApp.*.dll" ) )
								.BasedOn<IController>()
								.LifestyleTransient()
			);

			container.Register
			(
				AllTypes.FromAssemblyInDirectory( new AssemblyFilter( directory, "SampleApp.*.dll" ) )
								.BasedOn<ApiController>()
								.LifestyleTransient()
			);

			container.Register
			(
				Component.For<IDispatcher>()
					.ImplementedBy<NullDispatcher>()
					.LifeStyle.Is( LifestyleType.Singleton ),

				Component.For<IMessageBroker>()
					.ImplementedBy<MessageBroker>()
					.LifeStyle.Is( LifestyleType.Singleton )
			);

			container.Register
			(
				AllTypes.FromAssemblyInDirectory( new AssemblyFilter( directory, "SampleApp.*.dll" ) )
					.IncludeNonPublicTypes()
					.Where( t => !t.IsInterface && !t.IsAbstract && t.Is<IHandleMessage>() )
					.WithService.Select( ( type, all ) =>
					{
						var contracts = type.GetInterfaces()
							.Where( i => i.IsAttributeDefined<ContractAttribute>() )
							.ToArray();
						return contracts;
					} )
					.Configure( cr =>
					{
						cr.LifestyleSingleton();
					} )
			);

			container.Register
			(
				AllTypes.FromAssemblyInDirectory( new AssemblyFilter( directory, "SampleApp.*.dll" ) )
					.IncludeNonPublicTypes()
					.Where( t => !t.IsInterface && !t.IsAbstract && !String.IsNullOrWhiteSpace( t.Namespace ) && t.Namespace.EndsWith( ".Services" ) )
					.WithService.FirstInterface()
					.Configure( c =>
					{
						if ( c.Implementation.Is<IRequireToStart>() )
						{
							c.Start();
						}
					} )
			);

			container.Register
			(
				AllTypes.FromAssemblyInDirectory( new AssemblyFilter( directory, "SampleApp.*.dll" ) )
					.IncludeNonPublicTypes()
					.Where( t => !t.IsInterface && !t.IsAbstract && !String.IsNullOrWhiteSpace( t.Namespace ) && t.Namespace.EndsWith( ".Services.RequestScoped" ) )
					.WithService.FirstInterface()
					.LifestylePerWebRequest()
					.Configure( c =>
					{
						if ( c.Implementation.Is<IRequireToStart>() )
						{
							c.Start();
						}
					} )
			);

			container.Register
			(
				AllTypes.FromAssemblyInDirectory( new AssemblyFilter( directory, "SampleApp.*.dll" ) )
					.Where( t => !t.IsInterface && !t.IsAbstract && t.IsNested && t.Name.EndsWith( "Factory" ) )
					.WithService.Self()
					.LifestyleSingleton()
			);

			container.Register
			(
				Component.For<IDocumentStore>()
					.UsingFactoryMethod( () =>
					{
						var ds = new DocumentStore()
						{
							DefaultDatabase = "SampleApp",
							Url = "http://localhost:8080/",
							Credentials = new NetworkCredential( "RavenUser", "P@ssw0rd", "PESTILENCE" ),
						}.Initialize();

						return ds;
					} )
			);
		}
	}
}
